#include "tdp2_glfunctions.hpp"
#include "tdp2_glrenderdevice.hpp"

#define GPA(t, n) \
	do \
	{ \
		pfn = i->GetProcAddress("gl" #n);\
		if(!pfn)\
		{\
			*blameProc = "gl" #n;\
			return false;\
		}\
		this->n = static_cast<t>(pfn);\
	} while(0)

#define GPA_ALT(t, n, alt) \
	do \
	{ \
		pfn = i->GetProcAddress("gl" #n);\
		if(!pfn)\
		{\
			pfn = i->GetProcAddress("gl" #alt);\
			if(!pfn)\
			{\
				*blameProc = "gl" #n;\
				return false;\
			}\
		}\
		this->n = static_cast<t>(pfn);\
	} while(0)

namespace TDP
{
	namespace Rendering
	{
		bool GLFunctions::Initialize(const IGLInitializer *i, const char **blameProc)
		{
			void *pfn;

			// Link OpenGL calls

			GPA(PFNGLBEGINPROC, Begin);
			GPA(PFNGLENDPROC, End);
			GPA(PFNGLGETSTRINGPROC, GetString);
			GPA(PFNGLGETINTEGERVPROC, GetIntegerv);
			GPA(PFNGLCOMPRESSEDTEXIMAGE2DARBPROC, CompressedTexImage2DARB);
			GPA(PFNGLCOMPRESSEDTEXIMAGE3DARBPROC, CompressedTexImage3DARB);
			GPA(PFNGLGETTEXLEVELPARAMETERIVPROC, GetTexLevelParameteriv);
			GPA(PFNGLGENTEXTURESPROC, GenTextures);
			GPA(PFNGLDELETETEXTURESPROC, DeleteTextures);
			GPA(PFNGLBINDTEXTUREPROC, BindTexture);
			GPA(PFNGLTEXIMAGE2DPROC, TexImage2D);
			GPA(PFNGLTEXIMAGE3DPROC, TexImage3D);
			GPA(PFNGLTEXSUBIMAGE2DPROC, TexSubImage2D);
			GPA(PFNGLTEXSUBIMAGE3DPROC, TexSubImage3D);
			GPA(PFNGLCOMPRESSEDTEXSUBIMAGE2DARBPROC, CompressedTexSubImage2DARB);
			GPA(PFNGLCOMPRESSEDTEXSUBIMAGE3DARBPROC, CompressedTexSubImage3DARB);

			GPA(PFNGLPIXELSTOREIPROC, PixelStorei);
			GPA(PFNGLGETCOMPRESSEDTEXIMAGEARBPROC, GetCompressedTexImageARB);
			GPA(PFNGLGETERRORPROC, GetError);
			GPA(PFNGLTEXPARAMETERIPROC, TexParameteri);
			GPA(PFNGLGETTEXPARAMETERIV, GetTexParameteriv);

			GPA(PFNGLENABLEPROC, Enable);
			GPA(PFNGLDISABLEPROC, Disable);
			GPA(PFNGLENABLECLIENTSTATEPROC, EnableClientState);
			GPA(PFNGLDISABLECLIENTSTATEPROC, DisableClientState);

			GPA(PFNGLACTIVETEXTUREPROC, ActiveTexture);
			GPA(PFNGLCLIENTACTIVETEXTUREPROC, ClientActiveTexture);


			GPA(PFNGLBINDBUFFERARBPROC, BindBufferARB);
			GPA(PFNGLDELETEBUFFERSARBPROC, DeleteBuffersARB);
			GPA(PFNGLGENBUFFERSARBPROC, GenBuffersARB);
			GPA(PFNGLISBUFFERARBPROC, IsBufferARB);
			GPA(PFNGLBUFFERDATAARBPROC, BufferDataARB);
			GPA(PFNGLBUFFERSUBDATAARBPROC, BufferSubDataARB);
			GPA(PFNGLGETBUFFERSUBDATAARBPROC, GetBufferSubDataARB);
			GPA(PFNGLMAPBUFFERARBPROC, MapBufferARB);
			GPA(PFNGLUNMAPBUFFERARBPROC, UnmapBufferARB);
			GPA(PFNGLGETBUFFERPARAMETERIVARBPROC, GetBufferParameterivARB);
			GPA(PFNGLGETBUFFERPOINTERVARBPROC, GetBufferPointervARB);

			GPA(PFNGLPROGRAMSTRINGARBPROC, ProgramStringARB);
			GPA(PFNGLBINDPROGRAMARBPROC, BindProgramARB);
			GPA(PFNGLDELETEPROGRAMSARBPROC, DeleteProgramsARB);
			GPA(PFNGLGENPROGRAMSARBPROC, GenProgramsARB);
			GPA(PFNGLPROGRAMLOCALPARAMETER4FVARBPROC, ProgramLocalParameter4fvARB);

			GPA(PFNGLVERTEXPOINTERPROC, VertexPointer);
			GPA(PFNGLNORMALPOINTERPROC, NormalPointer);
			GPA(PFNGLCOLORPOINTERPROC, ColorPointer);
			GPA(PFNGLINDEXPOINTERPROC, IndexPointer);
			GPA_ALT(PFNGLVERTEXATTRIBPOINTERPROC, VertexAttribPointer, VertexAttribPointerARB);

			GPA(PFNGLDRAWRANGEELEMENTSPROC, DrawRangeElements);
			GPA(PFNGLDEPTHMASKPROC, DepthMask);
			GPA(PFNGLDEPTHFUNCPROC, DepthFunc);
			GPA(PFNGLCOLORMASKPROC, ColorMask);

			GPA(PFNGLBLENDFUNCPROC, BlendFunc);

			GPA(PFNGLCREATEPROGRAMOBJECTARBPROC, CreateProgramObjectARB);
			GPA(PFNGLCREATESHADEROBJECTARBPROC, CreateShaderObjectARB);
			GPA(PFNGLCOMPILESHADERARBPROC, CompileShaderARB);
			GPA(PFNGLSHADERSOURCEARBPROC, ShaderSourceARB);
			GPA(PFNGLGETUNIFORMLOCATIONARBPROC, GetUniformLocationARB);
			GPA(PFNGLATTACHOBJECTARBPROC, AttachObjectARB);
			GPA(PFNGLLINKPROGRAMARBPROC, LinkProgramARB);
			GPA(PFNGLUSEPROGRAMOBJECTARBPROC, UseProgramObjectARB);
			GPA(PFNGLDELETEOBJECTARBPROC, DeleteObjectARB);

			GPA(PFNGLGETOBJECTPARAMETERIVARBPROC, GetObjectParameterivARB);
			GPA(PFNGLGETINFOLOGARBPROC, GetInfoLogARB);

			GPA(PFNGLUNIFORM1FVARBPROC, Uniform1fvARB);
			GPA(PFNGLUNIFORM2FVARBPROC, Uniform2fvARB);
			GPA(PFNGLUNIFORM3FVARBPROC, Uniform3fvARB);
			GPA(PFNGLUNIFORM4FVARBPROC, Uniform4fvARB);

			GPA(PFNGLUNIFORMMATRIX2FVARBPROC, UniformMatrix2fvARB);
			GPA(PFNGLUNIFORMMATRIX2FVARBPROC, UniformMatrix3fvARB);
			GPA(PFNGLUNIFORMMATRIX2FVARBPROC, UniformMatrix4fvARB);

			GPA(PFNGLUNIFORM1IVARBPROC, Uniform1ivARB);
			GPA(PFNGLUNIFORM2IVARBPROC, Uniform2ivARB);
			GPA(PFNGLUNIFORM3IVARBPROC, Uniform3ivARB);
			GPA(PFNGLUNIFORM4IVARBPROC, Uniform4ivARB);

			GPA(PFNGLCLEARDEPTHPROC, ClearDepth);
			GPA(PFNGLCLEARPROC, Clear);
			GPA(PFNGLCOPYTEXSUBIMAGE2DPROC, CopyTexSubImage2D);
			GPA(PFNGLCOPYTEXIMAGE2DPROC, CopyTexImage2D);

			GPA(PFNGLGETATTRIBLOCATIONARBPROC, GetAttribLocationARB);
			GPA(PFNGLENABLEVERTEXATTRIBARRAYARBPROC, EnableVertexAttribArrayARB);
			GPA(PFNGLDISABLEVERTEXATTRIBARRAYARBPROC, DisableVertexAttribArrayARB);
			GPA(PFNGLBINDATTRIBLOCATIONARBPROC, BindAttribLocationARB);

			return true;
		}
	}
};
